#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <linux/ioport.h>

static int major;

static struct class *cls;
static struct device *dev;

static volatile unsigned long *gpio_con;
static volatile unsigned long *gpio_dat;

static int gpio_open(struct inode *inode, struct file *file){
	gpio_con = open("/dev/gpio/value",O_WRONLY);
	return 0;
}

/*ioctl函数 需要仿写成自己的 */
long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	struct gpio_priv *priv = filp->private_data;
	switch (cmd)
	{
		case :
			;
			break;
		case :
			;
			break;
		default:
			/*不能支持的命令*/
			return -ENOTTY;
	}

	return 0;
}

ssize_t gpio_read(struct file*filp, char __user*buf, size_t count, loff_t*f_pos)
{
	struct gpio_dev *dev = filp->private_data;// 获得私有数据指针
	int ret = 0;

	if(*f_pos > dev->size)// 判断文件是否已读完
		goto out;

	if(*f_pos + count > dev->size)// 如果读的数据过大
		count = dev->size- *f_pos;

	if(copy_to_user(buf,(void*)(dev->data+ *f_pos),count))    // 返回数据至用户空间
	{
		ret = -EFAULT;
		goto out;
	}

	*f_pos += count;
	ret = count;
out:
	return ret;
}

ssize_t gpio_write(struct file *filp, const char __user*buf, size_t count, loff_t*f_pos)
{
	struct gpio_dev *dev = filp->private_data;// 获得私有数据指针
	int ret = 0;

	if(*f_pos > MEMDEV_SIZE)// 判断文件是否已到结尾
		goto out;

	if(*f_pos + count > MEMDEV_SIZE)// 如果读的数据过大
		count = MEMDEV_SIZE - *f_pos;

	if(copy_from_user(dev->data+ *f_pos,buf,count))
	{
		ret = -EFAULT;
		goto out;
	}

	*f_pos += count;
	ret = count;

	if (dev->size < *f_pos)
		dev->size = *f_pos;

out:
	return ret;
}

/* 显示配置该gpio端口的pinmux */
int gpio_request(unsigned gpio, const char *label)

/* 标记gpio的使用方向包括输入、输出 */
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);

/* 创建文件direction 用来显示输入输出 */
static ssize_t gpio_direction_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	const struct gpio_desc  *desc = dev_get_drvdata(dev);
	unsigned        gpio = desc - gpio_desc;
	ssize_t         status;

	mutex_lock(&sysfs_lock);

	if (!test_bit(FLAG_EXPORT, &desc->flags))
		status = -EIO;
	else if (sysfs_streq(buf, "high"))
		status = gpio_direction_output(gpio, 1);
	else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
		status = gpio_direction_output(gpio, 0);
	else if (sysfs_streq(buf, "in"))
		status = gpio_direction_input(gpio);
	else
		status = -EINVAL;

	mutex_unlock(&sysfs_lock);
	return status ? : size;
}
static /* const */ DEVICE_ATTR(direction, 0644,
		gpio_direction_show, gpio_direction_store);

/* 获得和设置gpio引脚的值(对于输出) */
int gpio_get_value(unsigned gpio);
void gpio_set_value(unsigned gpio, int value);

/* gpio状态 */
struct gpio_priv {
	const char *name; // 名称，会生成/dev/gpio目录
	const char *default_trigger; //
	struct cdev cdev;/*字符设备cdev结构体*/
	unsigned     gpio; // GPIO引脚号
	unsigned char value;
	unsigned    retain_state_suspended : 1;
	unsigned    default_state : 2; // 默认状态
};

/* gpio个数以及状态描述 */
struct gpio_platform_data {
	int         num_gpio; // 一共有多少个GPIO
	const struct gpio_state *gpio; // 上面的结构体指针
}

static struct platform_device gpio = {
	.name = "gpio",
	.id = -1,
	.dev = {
		.platform_data = &gpio_info,
		.release = platformdev_release,
	},
};

static int __devinit gpio_probe(struct platform_device *pdev)
{
	struct resource *res;
	// 最后一个参数 0 表示第1个该类型的资源
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	gpio_con = ioremap(res->start, res->end - res->start + 1);
	gpio_dat = gpio_con + 1;

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	pin = res->start;

	printk("gpio_probe, found gpio\n");

	// 注册设备驱动 创建设备节点
	major = register_chrdev(0, "gpio", &gpio_fops);
	// 创建类
	cls = class_create(THIS_MODULE, "gpio");
	// 创建设备节点
	dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "gpio");

	return 0;
};

/* 需要写到probe中 */
static const struct file_operations gpio_fops = {
    .owner      = THIS_MODULE,
    .read       = gpio_read,
    .write      = gpio_write,
    .unlocked_ioctl = gpio_ioctl,
    .open       = gpio_open,
    .release    = gpio_release,
};

static struct platform_driver gpio_driver = {
    .probe      = gpio_probe,
    .remove     = __devexit_p(gpio_remove),
    .driver     = {
        .name   = "gpio",
        .owner  = THIS_MODULE,
        .of_match_table = of_gpio_match,
    },
};
module_platform_driver(gpio_driver);

static int __init gpio_init(void)
{
    return platform_driver_register(&gpio_driver);
}

static void gpio_exit(void)
{
    return platform_driver_unregister(&gpio_driver);
}

module_init(gpio_init);
module_exit(gpio_exit);
